package rpg.entity
{

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.PixelSnapping;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;

	import rpg.Utils.AStar;
	import rpg.Utils.ByteArrayUtil;
	import rpg.Utils.GameUtils;
	import rpg.Utils.Log;
	import rpg.Utils.Val;
	import rpg.data.ResData;
	import rpg.data.WorldMap;
	import rpg.interfaces.IUpdate;
	import rpg.manager.DataManager;
	import rpg.manager.GameManager;
	import rpg.resource.IMGResource;
	import rpg.resource.PreLoad;
	import rpg.resource.Resource;
	import rpg.resource.Resources;
	import rpg.update.Update;

	public class Map extends Update
	{
		private var _mapId : int;
		private var mapData : WorldMap;

		/**
		 * 加载器
		 */
		private var resources : Resources;
		/**
		 *小地图
		 */
		private var minMapImg : BitmapData;

		private var mosaicMatrix : Matrix = new Matrix();

		private var mapXML : XML;
		/**
		 * 地图总列数
		 */
		public var mapCols : int;
		/**
		 * 地图总行数
		 */
		public var mapRows : int;
		/**
		 * 可视区域相对于缓冲区的矩形
		 */
		public var viewRect : Rectangle;
		/**
		 * 区块宽度
		 */
		public var tileWidth : int;
		/**
		 * 区块高度
		 */
		public var tileHeight : int;
		/**
		 *地图宽高
		 */
		public var width : Number;
		public var height : Number;
		/**
		 * 可视区域宽高
		 */
		public var viewWidth : int;
		public var viewHeight : int;
		/**
		 *缓冲区域块大小
		 */
		public var bufferCols : int;
		public var bufferRows : int;
		/**
		 * 将地区区块复制到缓冲区中时的坐标
		 */
		private var bufferTilePoint : Point;
		/**
		 * 地图缓冲区
		 */
		public var bufferBD : BitmapData;
		/**
		 * 缓冲区相对于整场地图的矩形
		 */
		public var bufferRect : Rectangle;
		/**
		 *场景地图容器
		 */
		public var mapBD : Bitmap;
		/**
		 *加载完小地图才能更新
		 */
		private var updatable : Boolean;
		/**
		 * 保存加载过的地图区块的二维数组
		 */
		public var tileMapArray : Array;
		/**
		 * 当前帧的缓冲区起始X索引
		 */
		private var startCol : int;
		private var startRow : int;
		/**
		 *上次更新的开始格子
		 */
		private var oldStartCol : int = -1;
		private var oldStartRow : int = -1;
		/**
		 *上次更新的坐标
		 */
		private var oldX : Number;
		private var oldY : Number;
		/**
		 * 可视区域相对于整张地图的坐标
		 */
		public var viewX : int;
		public var viewY : int;
		/**
		 * 未加载时的地图黑块
		 */
		private var blackTileBD : BitmapData;
		/**
		 * 场景名称
		 */
		public var mapName : String;
		/**
		 * 场景目录
		 */
		private var fileUrl : String;

		private var maskArray : Array;
		public var maskSprite : Sprite;

		public function Map()
		{
			this.init();

		}

		override protected function init() : void
		{
			this.mapBD = new Bitmap(null , PixelSnapping.NEVER);
			this.bufferTilePoint = new Point();
			this.resources = Resources.getInstance();
			this.registerd(Update.MIDDEN);
//			this.loadMiniMap();
		}

		/**
		 *加载当前场景
		 *
		 */
		private function loadMap() : void
		{

		}


		/**
		 *加载小地图
		 *
		 */
		private function loadMiniMap() : void
		{
			mapData = DataManager.getInstance().getWorldMapById(mapId);
			mapXML = resources.getXml(mapData.mapName);
			var blockByteArray : ByteArray = resources.getByteArray(mapData.mapName + ".block");
			var astarArray : Array = blockByteArray.readObject() as Array;
			AStar.getInstance().init(astarArray);

			mapCols = mapXML.@mapCols;
			mapRows = mapXML.@mapRows;
			tileWidth = mapXML.@tileWidth;
			tileHeight = mapXML.@tileHeight;
			mapName = mapXML.@fileName;

			width = mapCols * tileWidth;
			height = mapRows * tileHeight;

			GameUtils.sceneWidth = width;
			GameUtils.sceneHeight = height;

			blackTileBD = new BitmapData(tileWidth , tileHeight , false);

			updatable = false;
			tileMapArray = [];
			for(var i : int ; i < mapCols ; i++)
			{
				tileMapArray.push([]);
			}

			maskArray = new Array();
			maskSprite = new Sprite();
			updateMaskArray();

			resize(GameUtils.stageWidth , GameUtils.stageHeight);
			fileUrl = PreLoad.sceneUrl + mapName + "/pic/";
			resources.preload(fileUrl + mapName + ".jpg" , ResData.IMAGE , Val.LOAD_LVEVEL_MAP , loadMiniMapComplete);
		}

		/**
		 *
		 * 更新遮罩数据
		 */
		private function updateMaskArray() : void
		{
			maskArray.length = 0;
			for each(var maskItem : XML in mapXML.masks.mask)
			{
				var maskDataArray : Array = String(maskItem.@maskarea).split(",");
				var maskObj : Object = {};
				maskObj.x = maskDataArray.shift();
				maskObj.y = maskDataArray.shift();
				maskObj.mask = maskDataArray;
				maskArray.push(maskObj);
			}
		}

		/**
		 * 屏幕大小 改变
		 * @param w
		 * @param h
		 *
		 */
		public function resize(w : int , h : int) : void
		{
			Log.print('设置地图显示宽高' , w , h);
			viewWidth = w;
			viewHeight = h;

			bufferCols = viewWidth / tileWidth + 3;
			bufferRows = viewHeight / tileHeight + 3;
			bufferCols = bufferCols > mapCols ? mapCols : bufferCols;
			bufferRows = bufferRows > mapRows ? mapRows : bufferRows;

			viewRect = new Rectangle(0 , 0 , viewWidth , viewHeight);

			if(bufferBD)
				bufferBD.dispose();
			bufferBD = new BitmapData(bufferCols * tileWidth , bufferRows * tileHeight , true , 0);
			bufferRect = bufferBD.rect.clone();

			oldX = -1;
			oldY = -1;
			oldStartCol = -1;
			oldStartRow = -1;
			this.mapBD.bitmapData = bufferBD;
		}

		private function loadMiniMapComplete(res : Resource) : void
		{
			minMapImg = IMGResource(res).bitmapData /*.clone()*/;
			updatable = true;
		}

		public function get mapId() : int
		{
			return _mapId;
		}

		public function set mapId(value : int) : void
		{
			_mapId = value;
			loadMiniMap();
		}

		override public function update(delay : uint) : void
		{
			if(!updatable)
				return;
			var isRefreshScreen : Boolean = true; //是否需要刷新屏幕
			var isRefreshBuffer : Boolean = true; //是否需要刷新缓存

			viewX = GameUtils.viewX;
			viewY = GameUtils.viewY;

			if(viewX == oldX && viewY == oldY)
			{
				isRefreshScreen = false;
			}

			oldX = viewX;
			oldY = viewY;

			if(isRefreshScreen)
			{
				// 计算出缓冲区开始的区块索引
				startCol = int(viewX / tileWidth) - 1;
				startRow = int(viewY / tileHeight) - 1;

				checkXBorder(); //检测更正x坐标
				checkYBorder(); //检测更正y坐标

				// 如果缓冲区的区块索引与上一帧相同，则本帧无需刷新缓冲区
				if(startCol == oldStartCol && startRow == oldStartRow)
					isRefreshBuffer = false;
				mapBD.scrollRect = viewRect;
				//加载遮罩
				var currentMaskArray : Array = maskArray.filter(filterPointDatas);
				buildMaskAreas(maskSprite , currentMaskArray);
				// 加载地图区块到缓冲区中
				if(isRefreshBuffer)
				{
					refreshBuffer();
				}
				oldStartRow = startRow;
				oldStartCol = startCol;
			}
		}

		/**
		 * 将遮挡区域画到其对应的画布上
		 *
		 * @param blockAreaBD
		 * @param blockAreaArray
		 *
		 */
		private function buildMaskAreas(maskSprite : Sprite , maskArray : Array) : void
		{
			maskSprite.graphics.clear();
			for each(var mask : Object in maskArray)
			{
				maskSprite.graphics.beginFill(0xabdcff , 0.2);
				var maskData : Array = mask.mask;
				var len : int = maskData.length;
				for(var i : int = 0 ; i < len ; i += 2)
				{
					var bufferX : int = int(maskData[i]) + int(mask.x) - viewX;
					var bufferY : int = int(maskData[i + 1]) + int(mask.y) - viewY;
					if(i == 0)
						maskSprite.graphics.moveTo(bufferX , bufferY);
					else
						maskSprite.graphics.lineTo(bufferX , bufferY);
				}
				maskSprite.graphics.endFill();
			}
		}

		/**
		 * 检测某一组坐标点是否有至少一个在当前屏幕矩形中
		 *
		 */
		private function filterPointDatas(element : * , index : int , arr : Array) : Boolean
		{
			var len : int = element.mask.length;
			for(var i : int = 0 ; i < len ; i += 2)
			{
				if(bufferRect.contains(int(element.mask[i]) + int(element.x) , int(element.mask[i + 1]) + int(element.y)))
				{
					return true;
				}
			}
			return false;
		}

		/**
		 * 刷新缓冲区
		 *
		 */
		private function refreshBuffer() : void
		{
			bufferRect.x = startCol * tileWidth;
			bufferRect.y = startRow * tileHeight;

			bufferBD.lock();
			//如果是滚动刷新缓冲区
			if(oldStartCol != -1 || oldStartRow != -1)
			{
				bufferBD.scroll(-(startCol - oldStartCol) * tileWidth , -(startRow - oldStartRow) * tileHeight);
			}

			var tileNeedFefresh : Boolean = false;
			var totalTileNum : int = 0;
			//将缓冲区对应的地图区块读入缓冲区中
			for(var rowCount : int = 0 ; rowCount < bufferRows ; rowCount++)
			{
				for(var colmnsCount : int = 0 ; colmnsCount < bufferCols ; colmnsCount++)
				{
					tileNeedFefresh = checkIsNeedFefreshBuffer(rowCount , colmnsCount);
					if(tileNeedFefresh)
					{
						bufferTilePoint.x = colmnsCount * tileWidth;
						bufferTilePoint.y = rowCount * tileHeight;

						var tileBD : BitmapData = getTileBD(colmnsCount + startCol , rowCount + startRow);
						if(tileBD != null)
						{
							bufferBD.copyPixels(tileBD , tileBD.rect , bufferTilePoint);
						}
					}
					clearBuffer(rowCount , colmnsCount);
				}
			}
			bufferBD.unlock();
		}

		private function clearBuffer(rowCount : int , colmnsCount : int) : void
		{
			//清除不在缓冲区中的地图区块位图
			//清除缓冲区上方一排
			if(rowCount == 0 && startRow > 0)
			{
				clearTileBD(colmnsCount + startCol , rowCount + startRow - 1);
				if(startCol > 0 && colmnsCount == 0)
				{
					clearTileBD(colmnsCount + startCol - 1 , rowCount + startRow - 1);
				}
				if(startCol < mapCols - bufferCols && colmnsCount == bufferCols - 1)
				{
					clearTileBD(colmnsCount + startCol + 1 , rowCount + startRow - 1);
				}
			}
			//清除缓冲区下方一排
			if(rowCount == bufferRows - 1 && startRow < mapRows - bufferRows)
			{
				clearTileBD(colmnsCount + startCol , rowCount + startRow + 1);
				if(startCol > 0 && colmnsCount == 0)
				{
					clearTileBD(colmnsCount + startCol - 1 , rowCount + startRow + 1);
				}
				if(startCol < mapCols - bufferCols && colmnsCount == bufferCols - 1)
				{
					clearTileBD(colmnsCount + startCol + 1 , rowCount + startRow - 1);
				}
			}
			//清除缓冲区左方一排
			if(colmnsCount == 0 && startCol > 0)
			{
				clearTileBD(colmnsCount + startCol - 1 , rowCount + startRow);
			}
			//清除缓冲区右方一排
			if(colmnsCount == bufferCols - 1 && startCol < mapCols - bufferCols)
			{
				clearTileBD(colmnsCount + startCol + 1 , rowCount + startRow);
			}
		}

		/**
		 * 释放指定x,y索引处的地图区块位图
		 * @param tileX
		 * @param tileY
		 *
		 */
		private function clearTileBD(tileX : int , tileY : int) : void
		{
			if(tileMapArray[tileX][tileY] && tileMapArray[tileX][tileY] != blackTileBD)
			{
				(tileMapArray[tileX][tileY] as BitmapData).dispose();
				tileMapArray[tileX][tileY] = null;
			}
		}

		/**
		 * 获取指定x,y索引处的地图区块位图
		 * @param tileX
		 * @param tileY
		 * @return
		 *
		 */
		private var imageItems : Array = [];

		private function getTileBD(tileX : int , tileY : int) : BitmapData
		{
			if(tileMapArray[tileX][tileY] == null || tileMapArray[tileX][tileY] == blackTileBD)
			{
				resources.preload(fileUrl + mapName + "_" + tileX + "_" + tileY + ".jpg" , ResData.IMAGE , (Val.LOAD_LVEVEL_MAP + int(tileY + "" + tileX)) , onTileLoadingComplete);
				if(minMapImg)
				{
					mosaicTile(tileX , tileY);
					return null;
				}
				tileMapArray[tileX][tileY] = blackTileBD;
			}
			return tileMapArray[tileX][tileY];
		}

		private function onTileLoadingComplete(res : Resource) : void
		{
			if(!tileMapArray)
				return;
			var urlArray : Array = res.url.split("/");
			var fileNameArray : Array = (urlArray[urlArray.length - 1] as String).split("_");

			var loadTileX : int = fileNameArray[1];
			var loadTileY : int = (fileNameArray[2] as String).split(".")[0];

			var bd : BitmapData = IMGResource(res).bitmapData;

			if(loadTileX < startCol || loadTileY < startRow)
				return;
			if(bd == null)
				Log.print("加载到的地图块为null?" , res.name);
			else
			{
				tileMapArray[loadTileX][loadTileY] = bd;
				bufferTilePoint.x = (loadTileX - startCol) * tileWidth;
				bufferTilePoint.y = (loadTileY - startRow) * tileHeight;
				bufferBD.copyPixels(bd , bd.rect , bufferTilePoint);
//				bufferBD.copyPixels(new BitmapData(200 , 200 , false , 0xff00ff) , bd.rect , bufferTilePoint);
			}
		}

		/**
		 * 为块添加马赛克效果
		 * @param tileX
		 * @param tileY
		 *
		 */
		private function mosaicTile(tileX : int , tileY : int) : void
		{
			if(minMapImg)
			{
				var tx : Number = (tileX * tileWidth) / GameUtils.mapRate;
				var ty : Number = (tileY * tileHeight) / GameUtils.mapRate;
				mosaicMatrix.identity();
				mosaicMatrix.translate(-tx , -ty);
				mosaicMatrix.scale(GameUtils.mapRate , GameUtils.mapRate);
				blackTileBD.draw(minMapImg , mosaicMatrix);
				bufferTilePoint.x = (tileX - startCol) * tileWidth;
				bufferTilePoint.y = (tileY - startRow) * tileHeight;

				bufferBD.copyPixels(blackTileBD , blackTileBD.rect , bufferTilePoint);
			}
		}

		/**
		 *检测是否需要刷新缓冲区域
		 * @return
		 *
		 */
		public function checkIsNeedFefreshBuffer(rowCount : int , colmnsCount : int) : Boolean
		{
			//如果是第一次构建缓冲区
			if((oldStartCol == -1 && oldStartRow == -1))
			{
				return true;
			}
			//如果是滚动刷新缓冲区
			if(startCol - oldStartCol > 0)
			{
				if(colmnsCount + (startCol - oldStartCol) >= bufferCols)
				{
					return true;
				}
			}
			else if(startCol - oldStartCol < 0)
			{
				if(colmnsCount < oldStartCol - startCol)
				{
					return true;
				}
			}

			if(startRow - oldStartRow > 0)
			{
				if(rowCount + (startRow - oldStartRow) >= bufferRows)
				{
					return true;
				}
			}
			else if(startRow - oldStartRow < 0)
			{
				if(rowCount < oldStartRow - startRow)
				{
					return true;
				}
			}
			return false;
		}

		/**
		 *检测更正x坐标
		 *
		 */
		private function checkXBorder() : void
		{
			// 走到了最左边
			if(startCol < 0)
			{
				startCol = 0;
				if(viewX <= 0)
					viewRect.x = 0;
				else
					viewRect.x = viewX;
			}
			// 走到了最右边
			else if((startCol + bufferCols) > mapCols)
			{
				startCol = mapCols - bufferCols;
				if((viewX + viewWidth) >= width)
				{
					viewRect.x = bufferBD.width - viewWidth;
				}
				else if(viewX >= (startCol * tileWidth + tileWidth * 2))
				{
					viewRect.x = tileWidth * 2 + viewX % tileWidth;
				}
				else
				{
					viewRect.x = viewX % tileWidth + tileWidth;
				}
			}
			// 走在中间区域
			else
			{
				viewRect.x = viewX % tileWidth + tileWidth;
			}
		}

		/**
		 *检测更正y坐标
		 *
		 */
		private function checkYBorder() : void
		{
			// 走到了最上方
			if(startRow < 0)
			{
				startRow = 0;
				if(viewY <= 0)
				{
					viewRect.y = 0;
				}
				else
				{
					viewRect.y = viewY;
				}
			}
			// 走到了最下方
			else if((startRow + bufferRows) > mapRows)
			{
				startRow = mapRows - bufferRows;

				if((viewY + viewHeight) >= height)
				{
					viewRect.y = bufferBD.height - viewHeight;
				}
				else if(viewY >= (startRow * tileHeight + tileHeight * 2))
				{
					viewRect.y = tileHeight * 2 + viewY % tileHeight;
				}
				else
				{
					viewRect.y = viewY % tileHeight + tileHeight;
				}
			}
			// 走在中间区域
			else
			{
				viewRect.y = viewY % tileHeight + tileHeight;
			}
		}


	}
}